<script setup>
import {
  onMounted,
  ref,
  reactive,
  getCurrentInstance,
  onActivated,
  onUnmounted,
  provide,
  nextTick
} from 'vue'
import { Dialog } from 'vant'
import anime from 'animejs/lib/anime.es.js'
import { useRouter } from 'vue-router'

import {
  login,
  getInitParam,
  sessionLog,
  sessionLogPageNew,
  sessionLogDetail,
  updateSessionLog,
  deleteOneSessionLog,
  getSessionLogById
} from '../../../service/api'
import {
  getUrlSearch,
  addTokenToUrl,
  getDateCategory,
  getDayjsCategory,
  decodeHTML
} from '../../../utils/token'
import { jumpHttp, isWx, isMobile, isWeixinMini } from '../../../utils/host'
import DigitalPeopleNew from '../components/DigitalpeopleNew.vue'
import ImagePeople from '../components/ImagePeople.vue'
import ChatBox from '../components/ChatBox.vue'
import Audios from '../components/Audios.vue'
import Worker from '../../../utils/worker.js?worker'
import defaultIcon from '../../../assets/img/dp-s.png'
import defaultUserIcon from '../../../assets/img/user.png'

import tongyi from '../../../assets/img/tongyi.png'
import xingpu from '../../../assets/img/xingpu.png'
import deepseek from '../../../assets/img/deepseek.png'
import doubao from '../../../assets/img/doubao.png'
import moonshot from '../../../assets/img/moon.ico'
import ernie from '../../../assets/img/wenxin.ico'

const router = useRouter()

const { appContext } = getCurrentInstance()
const proxy = appContext.config.globalProperties

const loaded = ref(false)
const digitPeopleRef = ref()
const starRef = ref()
const innerRef = ref()
const voiceRef = ref()
const chatBoxRef = ref()
const sessionId = ref()
const config = reactive({
  data: {},
  user: {}
})

// 数字人加载进度条
const progress = ref(0)
const onProgress = (e) => {
  progress.value = e
  innerRef.value.style.width = (progress.value * 4.76) / 100 + 'rem'
  starRef.value.style.left = (progress.value * 4.76) / 100 - 0.2 + 'rem'
}

// 数字人做对应的动作
const doAction = (action) => {
  console.log('调用模型动作', action)
  if (showModel.value === '1') {
    digitPeopleRef.value.animationCallback(action)
  }
}

// 播放声音
const playVoice = (voice) => {
  if (voiceRef.value) {
    voiceRef.value.voiceCallback(voice)
  }
}

// 语音或mp3结束
const voiceEnd = () => {
  chatBoxRef.value.voiceEnd()
}

// 点击任务身体
const onClickBody = () => {
  if (showModel.value === '1') {
    chatBoxRef.value.clickBodyVoiceAndAnimate()
  }
}

// 设置静音
const muted = ref(true)
const toggleMuted = () => {
  muted.value = !muted.value
  voiceRef.value.toogleMuted(muted.value)
  if (!window.player) {
    chatBoxRef.value.initPlayer()
  }
}

const needPadding = ref(true)

// 方言切换
const showLanPop = ref(false)
const canChooseLan = ref(false)
const lans = [
  {
    text: '中文普通话',
    value: 'zwpth'
  },
  // {
  //   text: "中英自由说",
  //   value: "zyzys",
  // },
  // {
  //   text: "湖北话",
  //   value: "hbh",
  // },
  // {
  //   text: "四川话",
  //   value: "sch",
  // },
  // {
  //   text: "粤语（简体）",
  //   value: "yyjt",
  // },
  // {
  //   text: "山西话",
  //   value: "sxh1",
  // },
  {
    text: '湖南话',
    value: 'hnh2'
  },
  {
    text: '河南话',
    value: 'hnh1'
  }
  // {
  //   text: "陕西话",
  //   value: "sxh2",
  // },
  // {
  //   text: "东北话",
  //   value: "dbh",
  // },
  // {
  //   text: "天津话",
  //   value: "tjh",
  // },
  // {
  //   text: "甘肃话",
  //   value: "gsh",
  // },
  // {
  //   text: "贵州话",
  //   value: "gzh",
  // },
  // {
  //   text: "云南话",
  //   value: "ynh",
  // },
  // {
  //   text: "江西话",
  //   value: "jxh",
  // },
  // {
  //   text: "广西话",
  //   value: "gxh",
  // },
  // {
  //   text: "宁夏话",
  //   value: "nxh",
  // },
  // {
  //   text: "山东话",
  //   value: "sdh",
  // },
  // {
  //   text: "苏州话",
  //   value: "szh",
  // },
  // {
  //   text: "浙江话",
  //   value: "zjh",
  // },
  // {
  //   text: "上海话",
  //   value: "shh",
  // },
  // {
  //   text: "维吾尔语",
  //   value: "wwey",
  // },
  // {
  //   text: "闽南语",
  //   value: "mny",
  // },
  // {
  //   text: "粤语（繁体）",
  //   value: "yyft",
  // },
]
const getLanIndex = (value) => {
  let ret = ''
  lans.forEach((item, index) => {
    if (item.value === value) {
      ret = index
    }
  })
  return ret
}
const localLanIndex = getLanIndex(window.localStorage.getItem('lanText')) || 0
const lan = ref(lans[localLanIndex].value)
const onConfirmLan = (e) => {
  lan.value = e.value
  window.localStorage.setItem('lanText', e.value)
  proxy.$toast(`您选择了${e.text}`)
  showLanPop.value = false
}

// 大模型切换
const showChangeModel = ref(false)
const models = [
  {
    text: 'Qwen-Plus',
    value: 'qwen-plus',
    description: '效果、速度、成本均衡',
    icon: tongyi
  },
  {
    text: 'Qwen-Max',
    value: 'qwen-max',
    description: '适合复杂任务，推理能力最强',
    icon: tongyi
  },
  {
    text: 'DeepSeek-R1',
    value: 'ep-20250207092149-pvc95',
    description: '大幅度提升了在数学、代码、自然语言能力的推理模型',
    icon: deepseek
  },
  {
    text: 'Doubao1.5-Pro',
    value: 'ep-20250219175323-5mvmg',
    description: '豆包全新一代主力模型，性能全面升级',
    icon: doubao
  }
  // {
  //   text: 'Moonshot-v1-32k',
  //   value: 'Moonshot-v1-32k',
  //   description: '优秀的语义理解、指令遵循和文本生成能力',
  //   icon: moonshot
  // },
  // {
  //   text: 'Ernie-4.5',
  //   value: 'Ernie-4.5',
  //   description: '多模态理解能力',
  //   icon: ernie
  // }
]

provide('models', models)

// 模型加载进度
const modelLogo = ref()
const showLoading = ref(false)
const loadingImg = ref()

// 是否使用3d模型
const showModel = ref()

// 模型动画
const showText = ref(false)
const isSmall = ref(false)
const hasExecuteAnimate = ref(false)
const animateScale = () => {
  showText.value = true
  if (hasExecuteAnimate.value) return
  hasExecuteAnimate.value = true
  anime({
    targets: '.header',
    height: '1.5rem',
    duration: 200,
    easing: 'linear'
  })
  anime({
    targets: '.chat-wraper',
    top: 0,
    duration: 200,
    easing: 'linear'
  })
  setTimeout(() => {
    anime({
      targets: '.infos',
      opacity: 1,
      duration: 300,
      easing: 'linear'
    })
  }, 400)
  isSmall.value = true
  if (showModel.value === '1') {
    digitPeopleRef.value.moveScale()
  } else if (showModel.value === '2') {
    anime({
      targets: '#imageModel',
      height: '1.5rem',
      width: '1.5rem',
      borderRadius: '50%',
      marginLeft: 0,
      duration: 200,
      easing: 'linear'
    })
  }
}
provide('animateScale', animateScale)
// 登录
const loginApp = () => {
  login()
    .then((res) => {
      window.access_token = res.access_token
      window.sessionStorage.setItem('access_token', res.access_token)
      config.user = res
      // if (res?.detail?.customerId == 485) {
      //   models.push({
      //     text: 'XingPu',
      //     value: 'xingpu',
      //     description: '星普大模型',
      //     icon: xingpu
      //   })
      // }
      getInitParam()
        .then((res) => {
          config.data = res
          // 是否自动跳转
          if (!isMobile() && res.autoAdaptHost) {
            window.location.replace(`./normal.html${window.location.search}`)
          }
          const agentList = res.agentInfoEntities || []
          if (agentList && agentList.length) {
            entityList.value.push(...agentList)
          }
          window.localStorage.setItem('config', JSON.stringify(config))
          showModel.value = res.showModel ? '1' : '2'
          loaded.value = showModel.value === '2'
          showLoading.value = true
          loadingImg.value = res.loadingAvatar || defaultIcon // 加载loading页面图标
          res.openVoice = 0 // 暂时设置为0（进来默认没有声音，不使用后台配置参数）
          sessionId.value = res.sessionId // 会话id
          proxy.$config = res
          document.title = res.serviceName
          modelLogo.value = res.robotJacket // 模型上衣
          showKefu.value = !!res.manServiceUrl
          headerText.value.t3 = res.welcomeMessage
        })
        .catch((err) => {
          proxy.$toast(err)
        })
    })
    .catch((err) => {
      proxy.$toast(err)
    })
}

const headerText = ref({
  t1: '',
  t2: '',
  t3: ''
})
const setHt = (p) => {
  if (p) {
    headerText.value.t1 = p.t1
    headerText.value.t2 = p.t2
    headerText.value.t3 = p.t3
  } else {
    headerText.value.t1 = ''
    headerText.value.t2 = ''
    headerText.value.t3 = config.data.welcomeMessage
  }
}
provide('headerText', headerText)
provide('setHt', setHt)

const worker = new Worker()
worker.onmessage = (e) => {
  if (e.data === 'refresh') {
    login().then((res) => {
      window.access_token = res.access_token
    })
  }
}

// 客服
const showKefu = ref(false)
const goKefu = () => {
  const url = config.data.manServiceToken
    ? addTokenToUrl(config.data.manServiceUrl, 'token', 'token')
    : config.data.manServiceUrl
  if (url === 'invalid url') {
    proxy.$toast('地址解析失败，请检查配置')
    return
  }
  jumpHttp(url)
}

// vant自定义css变量
const themeVars = {
  collapseItemContentPadding: '0'
}
// 对话记录
const activeNames = ref('2') // 列表面板展开项
const showPopover = ref(false) // 是否显示编辑弹窗
const popoverRef = ref() // 弹窗引用
const entityList = ref([]) // 智能体列表
const dialogueList = ref([]) // 对话记录列表
const loading = ref(false) // 是否加载中
const error = ref(false) // 是否加载失败
const finished = ref(false) // 是否加载完成
const pageSize = 20 // 每页显示条数
const current = ref(1) // 页码
const activeDialog = ref(null) // 编辑弹窗的对话
const activeDialogueIndex = ref(null) // 编辑弹窗的对话索引
let currentDateType = null // 对话列表当前日期类型
const retryCount = ref(0)
const retryLimit = 1 // 超时重试次数限制
const getSessionList = () => {
  sessionLog({
    current: current.value,
    size: pageSize
  })
    .then((res) => {
      if (res.records.length) {
        res.records.forEach((item) => {
          item.content = item.content || item.ask || '暂无标题'
          // const dateType = getDateCategory(new Date(item.createTime))
          const dateType = getDayjsCategory(item.createTime)
          if (dateType !== currentDateType) {
            dialogueList.value.push({
              type: 'title',
              content: dateType
            })
            currentDateType = dateType
          } else {
            item.active = false
          }
          dialogueList.value.push(item)
        })
      }
      if (res.records.length < pageSize) {
        finished.value = true
      } else {
        current.value++
      }
      loading.value = false
    })
    .catch((err) => {
      if (retryCount.value < retryLimit) {
        retryCount.value++
        getSessionList()
      } else {
        retryCount.value = 0
        loading.value = false
        error.value = true
      }
    })
}
const handleLongpress = (item, e) => {
  proxy.$toast.clear()
  activeDialog.value = item
  popoverRef.value.style.left = Number(e.x) - 40 + 'px'
  popoverRef.value.style.top = Number(e.y) - 130 + 'px'
  showPopover.value = true
  dialogueList.value.forEach((record, index) => {
    if (record.type !== 'title') {
      record.active = false
    }
    if (record.sessionId === activeDialog.value.sessionId) {
      activeDialogueIndex.value = index
    }
  })
  item.active = true
}
const deleteDialog = () => {
  showPopover.value = false
  Dialog.confirm({
    title: '是否删除所选的1个对话',
    message: '删除后的对话不可恢复',
    confirmButtonText: '删除',
    confirmButtonColor: '#FF001E'
  }).then(() => {
    deleteOneSessionLog(activeDialog.value.sessionId, true)
      .then((res) => {
        console.log(res)
        if (
          dialogueList.value[activeDialogueIndex.value - 1].type === 'title' &&
          dialogueList.value[activeDialogueIndex.value + 1].type === 'title'
        ) {
          dialogueList.value.splice(activeDialogueIndex.value - 1, 2)
        } else {
          dialogueList.value.splice(activeDialogueIndex.value, 1)
        }
        proxy.$toast('删除成功')
      })
      .catch(() => {
        proxy.$toast('删除失败')
      })
  })
}
const handleClickDialog = (item) => {
  const { appid, sessionId, qaList } = item
  if (appid) {
    // console.log('跳转智能体', { id: 'agent' + appid, sessionId: sessionId })
    window.sessionStorage.setItem('sessionId', sessionId)
    handleClickEntity({ id: 'agent' + appid })
    return
  }
  chatBoxRef.value.stopVoiceAndAnimate()
  voiceEnd()
  handleClickHistory(item)
}
// 获取对话详情
const handleClickHistory = async (item) => {
  try {
    // 点击对话列表的对话详情sessionId
    const { records } = await sessionLogDetail(item.sessionId, true)
    sessionId.value = item.sessionId
    const messages = []
    records[0].qaList.forEach((ele) => {
      const obj = {
        showInfo: true,
        isHistory: true,
        isTextEnd: true,
        type: '',
        message: '',
        opsStatus: ele.evaluate + '',
        uuid: ele.uuid
      }
      if (ele.type === 2) {
        obj.type = 'Bot'
      } else if (ele.type === 1) {
        obj.type = 'User'
      }
      obj.message = ele.content
        ? window.md.render(ele.content).replaceAll('&lt;br&gt;', '<br />')
        : '当前问题没有回答'
      messages.push(obj)
    })

    hideMine()
    chatBoxRef.value.showMessages(messages)
  } catch (err) {
    console.log(err)
  }
}
function getIndexHtmlPrefix(url) {
  // 找到index.html的位置
  const indexHtmlIndex = url.indexOf('index.html')
  // 截取从开始到index.html之前的所有字符
  if (indexHtmlIndex !== -1) {
    return url.substring(0, indexHtmlIndex)
  }
  return url
}
const handleClickEntity = (item) => {
  chatBoxRef.value.stopVoiceAndAnimate()
  voiceEnd()
  // 点击智能体。跳转到智能体对话页面
  const token = getUrlSearch(window.location.href, 'token')
  const customerServiceConfId = getUrlSearch(
    window.location.href,
    'customerServiceConfId'
  )
  const agentUrl = `entity.html?token=${token}&accessToken=${window.access_token}&customerServiceConfId=${customerServiceConfId}&id=${item.id}`
  const fullUrl = getIndexHtmlPrefix(window.location.href) + agentUrl
  if (isWx()) {
    console.log('完美校园环境')
    wanxiao.openNewWebview(fullUrl)
  } else if (isWeixinMini()) {
    console.log('微信小程序环境')
    wx.miniProgram.navigateTo({
      url: `/pages/webview/webview?url=${encodeURIComponent(fullUrl)}`
    })
  } else {
    window.location.href = agentUrl
  }
}
const addNewDialog = () => {
  // 检测当前对话列表是否有用户的对话
  let hasUserType = false
  const cMsgs = chatBoxRef.value.messages
  const len = chatBoxRef.value.messages.length
  for (let i = 0; i < len; i++) {
    if (cMsgs[i].type === 'User') {
      hasUserType = true
      break
    }
  }

  if (!hasUserType) {
    proxy.$toast('当前已在新对话中')
    hideMine()
  } else {
    chatBoxRef.value.stopVoiceAndAnimate()
    voiceEnd()
    getInitParam({}, true)
      .then((res) => {
        chatBoxRef.value.showMessages()
        sessionId.value = res.sessionId // 会话id
        config.data = res
        // 是否自动跳转
        if (!isMobile() && res.autoAdaptHost) {
          window.location.replace(`./normal.html${window.location.search}`)
        }
        window.localStorage.setItem('config', JSON.stringify(config))
        proxy.$config = res
        showKefu.value = !!res.manServiceUrl
        headerText.value.t3 = res.welcomeMessage
        hideMine()
      })
      .catch((err) => {
        proxy.$toast(err)
      })
  }
}

const showMine = ref(false)
const refreshKey = ref(Date.now())
const hideMine = (org) => {
  showMine.value = false
}
const handleShowMine = () => {
  error.value = false
  dialogueList.value = []
  current.value = 1
  retryCount.value = 0 // 重置重试次数
  finished.value = false
  showMine.value = true
  refreshKey.value = Date.now()
}

const handleCollapseChange = (val) => {
  if (val == '2') {
    refreshKey.value = Date.now()
  }
}

// 点击跳转搜索页面
const goSearch = () => {
  digitPeopleRef.value.stopRender()
  hideMine()
  setTimeout(() => {
    router.push({
      path: '/search'
    })
  }, 500)
}
// 标题重命名
const showChangeName = ref(false)
const inputRef = ref()
const newName = ref('')
const handleShowChangeName = () => {
  showChangeName.value = true
  showPopover.value = false
  nextTick(() => {
    inputRef.value.focus()
  })
}
const handleCloseChangeName = () => {
  showChangeName.value = false
  newName.value = ''
}
const handleConfirmChangeName = () => {
  const v = newName.value
  if (v.trim() === '') {
    proxy.$toast('请输入新的对话标题')
  } else if (v === activeDialog.value.content) {
    proxy.$toast('新标题不能和原标题相同')
  } else {
    updateSessionLog(
      {
        id: activeDialog.value.sessionId,
        title: v
      },
      true
    )
      .then((res) => {
        proxy.$toast('重命名成功')
        activeDialog.value.content = newName.value
        handleCloseChangeName()
      })
      .catch(() => {
        proxy.$toast('重命名失败')
      })
  }
}

onMounted(() => {
  loginApp()
  needPadding.value =
    getUrlSearch(window.location.href, 'NCPNavBarAlpha') === '0' && isWx()
  document.body.addEventListener('click', () => {
    showPopover.value = false
    dialogueList.value.forEach((item) => {
      if (item.type !== 'title') {
        item.active = false
      }
    })
  })
})

onActivated(() => {
  document.title = config.data.serviceName || '\u200E'
  if (digitPeopleRef.value) {
    digitPeopleRef.value.initRender()
  }
  if (window.sessionStorage.getItem('addNewFromSeachPage') === '1') {
    addNewDialog()
    window.sessionStorage.removeItem('addNewFromSeachPage')
  }
  if (window.sessionStorage.getItem('clickSearchItemFromSearchPage') === '1') {
    const sessionId = window.sessionStorage.getItem(
      'clickSearchItemFromSearchPageSession'
    )
    if (sessionId) {
      handleClickHistory({ sessionId: sessionId })
    }
    window.sessionStorage.removeItem('addNewFromSeachPage')
    window.sessionStorage.removeItem('clickSearchItemFromSearchPageSession')
  }
})
onUnmounted(() => {
  voiceEnd()
})
</script>
<template>
  <Audios v-if="sessionId" ref="voiceRef" @voice-end="voiceEnd" />
  <div class="appBg" v-if="(showModel === '1' && loaded) || showModel === '2'">
    <img src="../../../assets/img/bg.png" alt="" />
  </div>
  <div class="page-newindex" :class="{ padding: needPadding }">
    <div
      class="ops-box"
      v-if="(showModel === '1' && loaded) || showModel === '2'"
    >
      <div class="ops left-ops">
        <span class="mine" @click="handleShowMine" />
        <span class="new" @click="addNewDialog" />
      </div>
      <div class="ops right-ops">
        <span class="fankui" v-if="showKefu" @click="goKefu" />
        <span
          class="language"
          v-if="canChooseLan"
          @click.stop="showLanPop = true"
        />
        <span class="voice" :class="{ muted: muted }" @click="toggleMuted" />
      </div>
    </div>

    <div v-if="sessionId" class="header">
      <div v-if="showModel === '1'" id="digit" :class="{ small: isSmall }">
        <DigitalPeopleNew
          ref="digitPeopleRef"
          :model-logo="modelLogo"
          @on-progress="onProgress"
          @click-body="onClickBody"
          @is-loaded="loaded = true"
        />
      </div>
      <div
        v-else-if="showModel === '2'"
        id="imageModel"
        :class="{ small: isSmall }"
      >
        <ImagePeople :avatar="loadingImg" />
      </div>
      <div class="infos" v-if="showText">
        <span>{{ headerText.t1 }}</span>
        <span style="margin-top: 0.1rem"
          ><span style="color: #4792e4">{{ headerText.t2 }}</span
          ><span>{{ headerText.t3 }}</span></span
        >
      </div>
    </div>
    <div
      class="chat-wraper"
      :class="{ small: isSmall, hasBg: showModel === '1' && loaded }"
    >
      <ChatBox
        ref="chatBoxRef"
        :muted="muted"
        :session-id="sessionId"
        :lan="lan"
        :model="model"
        v-if="loaded && sessionId"
        @do-action="doAction"
        @play-voice="playVoice"
      />
    </div>
  </div>
  <div class="loading-wrap" v-if="showModel === '1' && !loaded">
    <div class="loading">
      <div class="logo">
        <img v-if="showLoading" :src="loadingImg" />
      </div>
      <div class="ai">
        <img src="../../../assets/img/AI.png" />
        <div class="loader loader-8" />
      </div>
      <div class="wraper">
        <div class="inner" ref="innerRef" />
        <img class="icon" ref="starRef" src="../../../assets/img/small.png" />
      </div>
    </div>
    <div class="footer">
      <span
        >{{
          config.data.serviceName || config.data.nickname || '本'
        }}应用含AI深度合成/生成式人工智能服务<br />禁止利用功能从事违法活动相关的风险提示<br />模型网信算备330110507206401230035号</span
      >
    </div>
  </div>
  <van-popup
    id="lanpop"
    :show="showLanPop"
    position="bottom"
    round
    @click-overlay="showLanPop = false"
    @click-close-icon="showLanPop = false"
  >
    <van-picker
      :columns="lans"
      :default-index="localLanIndex"
      @cancel="showLanPop = false"
      @confirm="onConfirmLan"
    />
  </van-popup>
  <van-popup
    id="minepop"
    :show="showMine"
    position="left"
    @click-overlay="showMine = false"
    safe-area-inset-bottom
    teleport="#app"
  >
    <div class="mine" v-swipeleft="hideMine">
      <div class="infos">
        <img
          class="avatar"
          :src="config.user.detail.customPic || defaultUserIcon"
        />
        <div class="info">
          <div class="top">
            <span class="name">{{
              config.user.detail.stuNo
                ? config.user.real_name
                : config.user.nick_name
            }}</span>
            <span class="outid" v-if="config.user.detail.stuNo">{{
              config.user.detail.stuNo
            }}</span>
            <span class="identity" v-if="config.user.detail.identityType">{{
              config.user.detail.identityType
            }}</span>
          </div>
          <span class="academy">{{
            config.user.detail.academy ||
            config.user.detail.department ||
            config.user.detail.customerName
          }}</span>
        </div>
      </div>
      <van-config-provider :theme-vars="themeVars">
        <van-collapse
          v-model="activeNames"
          accordion
          @change="handleCollapseChange"
        >
          <van-collapse-item
            name="1"
            style="
              border-radius: 0.15rem;
              overflow: hidden;
              margin-bottom: 0.3rem;
            "
            v-if="entityList.length > 0"
          >
            <template #title>
              <div class="d-head">
                <span class="a">智能体</span>
              </div>
            </template>
            <div class="dialogue-list dialogue-list-entity">
              <div class="entities" @touchstart="showPopover = false">
                <div
                  class="item"
                  v-for="item in entityList"
                  :key="item.id"
                  @click.stop="handleClickEntity(item)"
                >
                  <img :src="item.icon" />
                  <div class="content">
                    <div class="item-content-title">{{ item.name }}</div>
                    <div class="item-content-info">{{ item.description }}</div>
                  </div>
                </div>
              </div>
            </div>
          </van-collapse-item>
          <van-collapse-item
            name="2"
            style="
              border-radius: 0.15rem;
              overflow: hidden;
              margin-bottom: 0.3rem;
            "
          >
            <template #title>
              <div class="d-head">
                <span class="t">对话列表</span>
              </div>
            </template>
            <div class="dialogue-list" v-if="sessionId">
              <div class="d-search">
                <!-- <span class="t">对话列表</span> -->
                <!-- 点击跳转搜索 -->
                <div class="input" @click="goSearch">
                  <img src="../../../assets/img/search1.png" />
                  <input type="text" placeholder="搜索对话记录" readonly />
                </div>
              </div>
              <div
                class="dlists"
                @touchstart="showPopover = false"
                :key="refreshKey"
              >
                <van-list
                  v-model:loading="loading"
                  v-model:error="error"
                  @load="getSessionList"
                  :finished="finished"
                  finished-text="没有更多了"
                  error-text="请求失败，点击重新加载"
                >
                  <div
                    class="item"
                    :class="{ title: item.type === 'title' }"
                    v-for="item in dialogueList"
                    :key="item.sessionId"
                  >
                    <div
                      v-if="item.type !== 'title'"
                      class="content oneline"
                      :class="{ active: item.active }"
                      v-longpress="
                        (e) => {
                          handleLongpress(item, e)
                        }
                      "
                      @click.stop="handleClickDialog(item)"
                    >
                      {{ decodeHTML(item.content) }}
                    </div>
                    <div v-else class="type">
                      {{ item.content }}
                    </div>
                  </div>
                </van-list>
              </div>
              <div ref="popoverRef" class="edit-popover" v-show="showPopover">
                <div class="ops edit" @click.stop="handleShowChangeName">
                  <img src="../../../assets/img/edit.png" />
                  <span>重命名</span>
                </div>
                <div class="ops delete" @click.stop="deleteDialog">
                  <img src="../../../assets/img/delete.png" />
                  <span>删除</span>
                </div>
              </div>
            </div>
          </van-collapse-item>
        </van-collapse>
      </van-config-provider>
      <div class="add-new" @click="addNewDialog">新建对话</div>
    </div>
  </van-popup>
  <van-popup
    id="namepop"
    :show="showChangeName"
    position="bottom"
    @click-overlay="handleCloseChangeName"
  >
    <div class="change-name">
      <div class="title">重命名对话标题</div>
      <input
        v-model="newName"
        ref="inputRef"
        type="text"
        placeholder="请输入新的对话标题"
        maxlength="20"
      />
      <div class="btns">
        <span class="btn cancel" @click="handleCloseChangeName">取消</span>
        <span class="btn confirm" @click="handleConfirmChangeName">确认</span>
      </div>
    </div>
  </van-popup>
</template>

<style lang="less">
.label-content {
  padding: 0.2rem 0.32rem;
  border: 1px solid #d51212;
}
.appBg {
  position: absolute;
  width: 100%;
  height: 100%;
  img {
    display: block;
    width: 100%;
    height: 100%;
  }
}
.dialogue-list-entity {
  min-height: 1.5rem !important;
  padding-bottom: 0 !important;
}
.page-newindex {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 0.32rem 0 0;
  &.padding {
    padding-top: 1.5rem;
  }
  .ops-box {
    height: 0.56rem;
    margin-bottom: 0.2rem;
    padding: 0 0.32rem;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    .ops {
      display: flex;
    }
    .left-ops {
      span {
        margin-right: 0.15rem;
        &:last-child {
          margin-right: 0;
        }
      }
      .mine {
        width: 0.56rem;
        height: 0.56rem;
        background-image: url('../../../assets/img/menu.png');
        background-size: 100% 100%;
        border-radius: 50%;
      }
      .new {
        width: 0.56rem;
        height: 0.56rem;
        background-image: url('../../../assets/img/new-dialog.png');
        background-size: 100% 100%;
        border-radius: 50%;
      }
    }
    .right-ops {
      flex-direction: row-reverse;
      span {
        margin-left: 0.15rem;
        &:last-child {
          margin-left: 0;
        }
      }
      .voice {
        width: 0.56rem;
        height: 0.56rem;
        background-image: url('../../../assets/img/voice1.png');
        background-size: 100% 100%;
      }
      .muted {
        width: 0.56rem;
        height: 0.56rem;
        background-image: url('../../../assets/img/voice0.png');
        background-size: 100% 100%;
      }
      .language {
        width: 0.56rem;
        height: 0.56rem;
        background-image: url('../../../assets/img/lan.png');
        background-size: 100% 100%;
      }
      .fankui {
        width: 0.56rem;
        height: 0.56rem;
        background-image: url('../../../assets/img/kefu.png');
        background-size: 100% 100%;
      }
    }
  }
  .header {
    width: 100%;
    height: 3.2rem;
    position: relative;
    padding: 0 0.32rem;
    #digit {
      width: 100%;
      height: 3.2rem;
      margin: 0 auto;
      overflow: hidden;
      background-color: rgba(255, 255, 255, 0);
      transform-origin: 50% 0;
    }
    #digit.small {
      width: 3.2rem;
      height: 3.2rem;
      background-image: url('../../../assets/img/s-bg.png');
      background-size: 100% 100%;
    }
    #imageModel {
      width: 3.2rem;
      height: 3.2rem;
      overflow: hidden;
      margin: 0 auto;
    }
    #imageModel.small {
      width: 3.2rem;
      height: 3.2rem;
      background-image: url('../../../assets/img/s-bg.png');
      background-size: 100% 100%;
    }
    .infos {
      position: absolute;
      top: 0;
      left: 1.6rem;
      width: 5.5rem;
      height: 1.5rem;
      display: flex;
      flex-direction: column;
      justify-content: center;
      padding-left: 0.4rem;
      font-size: 0.3rem;
      opacity: 0;
      font-weight: bold;
      color: #333;
    }
  }
  .chat-wraper {
    width: 100%;
    flex: 1;
    z-index: 99;
    position: relative;
    padding: 0.2rem 0.32rem 0;
    &.hasBg {
      background: linear-gradient(180deg, #d1f3ff 0%, #dcf5fd 100%);
    }
    &.small.hasBg {
      background: transparent;
    }
  }
}
.loading-wrap {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: white;
  z-index: 100;
  .loading {
    width: 4.76rem;
    height: 2rem;
    box-sizing: content-box;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    .logo {
      height: 1.2rem;
      overflow: hidden;
      img {
        display: block;
        width: 1rem;
        height: auto;
        margin: 0 auto 0.2rem;
      }
    }
    .ai {
      display: flex;
      justify-content: center;
      align-items: center;
      img {
        width: 1.44rem;
        height: 0.3rem;
        margin-right: 0.3rem;
      }
      .loader {
        width: 0.3rem;
        height: 0.3rem;
        border-radius: 50%;
        display: inline-block;
        position: relative;
        vertical-align: middle;
        font-size: 0;
      }
      .loader,
      .loader:before,
      .loader:after {
        animation: 1s infinite ease-in-out;
      }
      .loader:before,
      .loader:after {
        width: 0.28rem;
        height: 0.28rem;
        border-radius: 50%;
        position: absolute;
        top: 0;
        left: 0;
      }

      .loader-8:before,
      .loader-8:after {
        content: '';
        transform: scale(0);
        animation: loader8 1.5s infinite ease-in-out;
      }
      .loader-8:before {
        background-color: #5baef9;
      }
      .loader-8:after {
        background-color: #8bc8ff;
      }
      .loader-8:after {
        animation-delay: 0.75s;
      }

      @keyframes loader8 {
        0% {
          transform: translateX(-100%) scale(0);
        }
        50% {
          transform: translateX(0%) scale(1);
        }
        100% {
          transform: translateX(100%) scale(0);
        }
      }
    }
    .wraper {
      width: 100%;
      height: 0.3rem;
      padding: 0 0.06rem;
      background-color: #e2f1fc;
      border-radius: 0.16rem;
      position: absolute;
      bottom: 0;
      left: 0;
      .inner {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        height: 0.2rem;
        width: 0;
        background: linear-gradient(90deg, #b6e9fc 0%, #79b9fa 100%);
        border-radius: 0.1rem;
        z-index: 1;
      }
      .icon {
        width: 0.6rem;
        height: 0.6rem;
        display: block;
        position: absolute;
        left: -0.2rem;
        top: -0.16rem;
        z-index: 2;
        // animation: rotate 2s linear infinite;
      }
    }
  }
  .footer {
    width: 100%;
    text-align: center;
    position: absolute;
    bottom: 1rem;
    left: 50%;
    transform: translateX(-50%);
    font-size: 0.2rem;
    color: #818181;
    letter-spacing: 2px;
    line-height: 0.3rem;
  }
}

#modelpop {
  .model-item {
    display: flex;
    align-items: center;
    .model-icon {
      width: 0.56rem;
      height: 0.56rem;
      img {
        width: 100%;
        height: 100%;
      }
    }
    .model-info {
      display: flex;
      flex-direction: column;
      margin-left: 0.2rem;
      width: 4rem;
      .model-text {
        font-size: 0.24rem;
      }
      .model-description {
        font-size: 0.16rem;
        color: #999;
        margin-top: 0.05rem;
      }
    }
  }
}
</style>
